package com.ys.erp.stage_mall_service.utils;

import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ys.erp.common.enums.RedisKey;
import com.ys.erp.common.enums.old.StatusOldEnum;
import com.ys.erp.entity.data.bean.RefundRecord;
import com.ys.erp.framework.exception.YsException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;


/**
 * @author lwj
 * @date 2023/4/21
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class WxUtil {

    @Value("${wx.app-id}")
    private String appId;

    @Value("${wx.app-secret}")
    private String appSecret;

    @Value("${wx.refundCallbackUrl}")
    private String refundUrl;

    private final RestTemplate restTemplate;

    private final RedisTemplate<String, String> redisTemplate;

    private final CloseableHttpClient httpClient;

    public String getAccessToken() {
        String redisToken = redisTemplate.opsForValue().get(RedisKey.Enums.WX_ACCESS_TOKEN.getKey());
        if (ObjectUtils.isNotEmpty(redisToken)) {
            return redisToken;
        }
        String url = "https://api.weixin.qq.com/cgi-bin/token?"
                + "grant_type=client_credential"
                + "&appid=" + appId
                + "&secret=" + appSecret;
        String resStr = restTemplate.getForObject(url, String.class);
        JSONObject resJson = JSONObject.parseObject(resStr);
        if (ObjectUtils.isEmpty(resJson)) {
            throw new YsException(-1, "请求错误");
        }
        if (!resJson.containsKey("access_token") || ObjectUtils.isEmpty(resJson.containsKey("access_token"))) {
            throw new YsException(-1, "请求错误");
        }
        String accessToken = resJson.getString("access_token");
        redisTemplate.opsForValue().set(RedisKey.Enums.WX_ACCESS_TOKEN.getKey(), accessToken, 55, TimeUnit.MINUTES);
        return accessToken;
    }

    public void refund(RefundRecord refundRecord, Long totalMoney) {
        log.info("发起WX退款,{}", JSONObject.toJSONString(refundRecord));
        String url = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
        CloseableHttpResponse execute = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode param = objectMapper.createObjectNode();
            param.put("out_trade_no", refundRecord.getWxOutTradeNo());
            param.put("out_refund_no", refundRecord.getWxRefundNo());
            param.put("reason", "你的售后订单已退款");
            param.put("notify_url", refundUrl);
            param.put("funds_account", "AVAILABLE");
            JSONObject amountObj = new JSONObject();
            amountObj.put("refund", refundRecord.getRefundMoney());
            amountObj.put("total", totalMoney);
            amountObj.put("currency", "CNY");
            param.putPOJO("amount", amountObj);
            objectMapper.writeValue(bos, param);
            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            execute = httpClient.execute(httpPost);
        } catch (Exception e) {
            refundRecord.setRefundStatus(StatusOldEnum.REFUND_FAIL.getStatus());
            refundRecord.setRefundFailTime(LocalDateTime.now());
            refundRecord.setRefundFailRemark(e.getMessage());
            return;
        }
        int statusCode = execute.getStatusLine().getStatusCode();
        org.apache.http.HttpEntity entity = execute.getEntity();
        try {
            String resStr = EntityUtils.toString(entity);
            log.info("微信发起退款响应参数，{}", resStr);
            JSONObject resObj = JSONObject.parseObject(resStr);
            if (statusCode != HttpStatus.SC_OK) {
                refundRecord.setRefundStatus(StatusOldEnum.REFUND_FAIL.getStatus());
                refundRecord.setRefundFailTime(LocalDateTime.now());
                refundRecord.setRefundFailRemark("退款失败，错误信息：" + resStr);
                return;
            }
            refundRecord.setWxRefundId(resObj.getString("refund_id"));
            String status = resObj.getString("status");
            LocalDateTime now = LocalDateTime.now();
            if ("SUCCESS".equals(status)) {
                //成功
                refundRecord.setRefundStatus(StatusOldEnum.REFUND_SUCCESS.getStatus());
                refundRecord.setRefundOkTime(now);
                refundRecord.setRefundingTime(now);
            } else if ("PROCESSING".equals(status)) {
                //退款中
                refundRecord.setRefundStatus(StatusOldEnum.REFUNDING.getStatus());
                refundRecord.setRefundingTime(now);
            } else {
                refundRecord.setRefundStatus(StatusOldEnum.REFUND_FAIL.getStatus());
                refundRecord.setRefundFailTime(now);
                refundRecord.setRefundFailRemark("退款异常，参数：" + resStr);
            }
        } catch (Exception e) {
            refundRecord.setRefundStatus(StatusOldEnum.REFUND_FAIL.getStatus());
            refundRecord.setRefundFailTime(LocalDateTime.now());
            refundRecord.setRefundFailRemark("请求成功，解析异常：" + e.getMessage());
        }
    }

}
